#pragma once

#include <cstdio>
#include <iostream>
#include <signal.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

void daemonize()
{
    int fd = 0;
    // 1. 忽略SIGPIPE
    signal(SIGPIPE, SIG_IGN);

    // 2. 更改进程的工作目录
    // chdir();

    // 3. 让自己不要成为进程组组长
    if (fork() > 0)
        exit(0); // 父进程退出了管都不用管，因为父进程有自己的父进程(bash)

    // 4. 设置自己是一个独立的会话 -- 不受登录退出的影响
    setsid();

    // 5. 重定向0, 1, 2
    if ((fd = open("/dev/null", O_RDWR)) != -1) // fd == 3
    {
        dup2(fd, STDIN_FILENO);
        dup2(fd, STDOUT_FILENO);
        dup2(fd, STDERR_FILENO);

        // 6. 关闭掉不需要的fd -- 别浪费了就关掉了
        if(fd > STDERR_FILENO)
            close(fd);
    }

    // 3, 4, 5这三步，是网络服务器写守护进程时，必写的三步

    // close(0,1,2);这种做法严重不推荐
}

// 重定向的原因：
// daemonize();函数实在网络服务器启动之前调用的
// 那么serverTcp服务器里一定有大量的cout cerr 打印日志的行为
// 我们调用setsid，创建一个会话，已经和终端没有关系了
// 一个会话绑定上终端(命令行界面)，是一个字符式的模拟终端
// Linux中是bash进程和终端强关联，终端也是文件是被打开的
// 当前的进程就可以从终端里读，向终端里写入
// 一旦将进程转变为守护进程，它就会与终端断开关联
// 也就是说它不再与终端会话相关联，这意味着守护进程不再受用户登录或注销的影响，并且不会与用户直接交互。
// 在setsid里就自动将进程和终端去关联了
// 去关联之后就不能使用cin cout cerr因为0,1,2描述符已经和终端去关联了，后续程序一写就退出了。